package com.moli.iov.notify.remote.impl;

import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.moli.iov.base.model.po.VehicleBase;
import com.moli.iov.base.remote.IVehicleBaseRemoteService;
import com.moli.iov.down.enums.OperateTypeEnum;
import com.moli.iov.handle.alarm.enums.AlarmCodeCollectionEnum;
import com.moli.iov.handle.alarm.enums.AlarmCodeEnum;
import com.moli.iov.notify.communication.template.*;
import com.moli.iov.notify.config.SmsProperties;
import com.moli.iov.notify.enums.MailUsedEnum;
import com.moli.iov.notify.enums.MessageTypeEnum;
import com.moli.iov.notify.enums.SendStatusEnum;
import com.moli.iov.notify.enums.SmsUsedEnum;
import com.moli.iov.notify.enums.StatusEnum;
import com.moli.iov.notify.model.dto.MailDto;
import com.moli.iov.notify.model.dto.MessageTemplateDto;
import com.moli.iov.notify.model.dto.NoticeMessageCenterDto;
import com.moli.iov.notify.model.dto.SmsDto;
import com.moli.iov.notify.model.po.NoticeAlarm;
import com.moli.iov.notify.model.po.NoticeMail;
import com.moli.iov.notify.model.po.NoticeSms;
import com.moli.iov.notify.model.po.NoticeVehicleCtl;
import com.moli.iov.notify.remote.INoticeMessageCenterRemoteService;
import com.moli.iov.notify.service.INoticeAlarmService;
import com.moli.iov.notify.service.INoticeMailService;
import com.moli.iov.notify.service.INoticeSmsService;
import com.moli.iov.notify.service.INoticeVehicleCtlService;
import com.moli.iov.notify.util.MailUtil;
import com.moli.iov.notify.util.SendSmsUtil;
import com.moli.iov.rest.RestResponse;
import com.moli.iov.util.DateUtil;
import com.moli.iov.util.JsonUtils;
import com.moli.iov.util.StringUtil;
import java.util.Date;
import java.util.HashMap;
import java.util.Map;
import lombok.extern.slf4j.Slf4j;
import org.apache.dubbo.config.annotation.Reference;
import org.apache.dubbo.config.annotation.Service;
import org.springframework.beans.factory.annotation.Autowired;

/**
 *
 *  According to vehicle information send alarm or vehicle control sms or mail.
 *
 * @author OAK
 * @version 3.0
 * @since 2019/10/12 9:42 AM.
 */
@Slf4j
@Service(group = "${service.group}")
public class NoticeMessageCenterRemoteServiceImpl implements INoticeMessageCenterRemoteService {

    @Reference(group = "${service.group}",check = false)
    IVehicleBaseRemoteService vehicleBaseRemoteService;

    @Autowired
    INoticeAlarmService noticeAlarmService;

    @Autowired
    INoticeVehicleCtlService noticeVehicleCtlService;

    @Autowired
    INoticeMailService noticeMailService;

    @Autowired
    INoticeSmsService noticeSmsService;

    @Autowired
    MailUtil mailHelper;

    @Autowired
    SendSmsUtil smsHelper;

    @Autowired
    private SmsProperties smsProperties;

    /**
     * alarm level constant collection.
     */
    final String [] alarmLevels = {"一", "二", "三"};

    /**
     * According notice communication center data transfer object for trigger send a mail or sms.
     * @param noticeMessageCenterDto Notice communication center data transfer object.
     * @return a rest response.
     */
    @Override
    public RestResponse trigger(NoticeMessageCenterDto noticeMessageCenterDto) {
        String vin = noticeMessageCenterDto.getVin(),
        operatorName = noticeMessageCenterDto.getOperatorName(),
        vehicleNumber,  subject, messageSourceValue;
        Integer messageType = noticeMessageCenterDto.getMessageType(),
                messageSource = noticeMessageCenterDto.getMessageSource(),
                alarmLevel = 0, messageSourceId;
        boolean enabledSMS, enabledMail;
        if (messageType == null) {
            return RestResponse.failure("消息类别不能为空！");
        }
        MessageTypeEnum messageTypeEnum = MessageTypeEnum.valueOf(messageType);
        try {
            VehicleBase vehicleBase = vehicleBaseRemoteService.getVehicleBaseByVin(vin);
            if (vehicleBase == null) {
                return RestResponse.failure("没有找到该车架号" + vin + "的车辆信息");
            }
            Long companyId = vehicleBase.getCompanyId();
            if (companyId == null) {
                return RestResponse.failure("没有找到该车架号" + vin + "的关联的企业");
            }
            vehicleNumber = vehicleBase.getLicense();
            if (vehicleNumber == null) {
                return RestResponse.failure("没有找到该车架号" + vin + "的车牌号");
            }
            if (MessageTypeEnum.ALARM.getMessageCode() == messageType) {
                subject = "实时报警通知";
                AlarmCodeEnum alarmEnum = AlarmCodeEnum.getEnum(messageSource);
                messageSourceValue = alarmEnum.getMsg();
                alarmLevel = alarmEnum.getLevel();
                AlarmCodeCollectionEnum alarmCodeCollectionEnum = AlarmCodeCollectionEnum.getAlarmCodeCollectionByChildrenFlag(messageSource);
                if (alarmCodeCollectionEnum == null) {
                    return RestResponse.failure("没有找到该车架号" + vin + "的报警集合类型");
                }
                NoticeAlarm noticeAlarm = noticeAlarmService.queryNoticeAlarmByProperties(companyId, alarmCodeCollectionEnum.getFlag(), alarmLevel);
                if (noticeAlarm == null) {
                    return RestResponse.failure("该车牌号" + vehicleNumber + "没有报警通知。");
                }
                messageSourceId = noticeAlarm.getId();
                enabledSMS = noticeAlarm.getSmsUsed() == SmsUsedEnum.ENABLED.getStatusCode();
                enabledMail = noticeAlarm.getMailUsed() == MailUsedEnum.ENABLED.getStatusCode();
            } else {
                messageSourceValue = OperateTypeEnum.getMsg(messageSource);
                subject = String.format("%s车辆%s控制通知", vehicleNumber, messageSourceValue);

                NoticeVehicleCtl noticeVehicleCtl = noticeVehicleCtlService.queryNoticeVehicleCtlByProperties(companyId, messageSource);
                if (noticeVehicleCtl == null) {
                    return RestResponse.failure("该车牌号" + vehicleNumber + "没有控车通知。");
                }
                messageSourceId = noticeVehicleCtl.getId();
                enabledSMS = noticeVehicleCtl.getSmsUsed() == SmsUsedEnum.ENABLED.getStatusCode();
                enabledMail = noticeVehicleCtl.getMailUsed() == MailUsedEnum.ENABLED.getStatusCode();
            }
            if(StringUtil.isNotBlank(messageSourceValue)){
                messageSourceValue = messageSourceValue.replace("报警", "");
            }
            if (enabledMail) {
                sendMail(companyId, messageType, messageSourceId, vehicleNumber, subject, operatorName,
                        messageSourceValue);
            } else {
                log.warn("该车牌号{}邮件发送已经被禁用，请启用邮件后在发送，发送失败。", vehicleNumber);
            }
            if (enabledSMS) {
                sendSMS(companyId, messageType, messageSourceId, vehicleNumber, operatorName, messageSourceValue, alarmLevel);
            } else {
                log.warn("该车牌号{}短信发送已经被禁用，请启用短信后在发送，发送失败。", vehicleNumber);
            }
        }catch(Exception ex){
            log.error("send mail or sms find a fail, {}", ex);
            return RestResponse.failure(ex.getMessage());
        }
        return RestResponse.success("该车牌号" + vehicleNumber  + messageTypeEnum.getMsg() + "消息发送成功。");
    }

    /**
     * According to mail source and vehicle number for send a mail.
     * @param mailSource Mail source.
     * @param vehicleNumber Vehicle number.
     * @return a rest response.
     */
    @Override
    public RestResponse sendTo(String mailSource, String vehicleNumber) {
        log.info("发送邮件 》》 mailSource:{},vin:{}",mailSource,vehicleNumber);
        String mailSubject = "车辆上线提醒";
        try{
            String[] mailTos = mailSource.split(",");
            for (String mailTo : mailTos) {
                MailDto mailDto = new MailDto();
                mailDto.setSubject(mailSubject);
                mailDto.setTo(mailTo);
                mailDto.setStatus(SendStatusEnum.SUCCESS.getFlag());
                MessageTemplateDto messageTemplateDto = new MessageTemplateDto();
                messageTemplateDto.setMailTo(mailTo);
                messageTemplateDto.setVehicleNumber(vehicleNumber);
                CommunicationTemplate communicationTemplate = new AttentionCommunicationTemplate();
                String message = CommunicationBuilder.builder(new ConcreteCommunicationTemplate(communicationTemplate))
                        .compile(messageTemplateDto).orElse("");
                mailDto.setText(message);
                mailHelper.sendMail(mailDto);
            }
        }catch(Exception ex){
            log.error("send mail or sms find a fail, {}", ex);
            return RestResponse.failure(ex.getMessage());
        }
        return RestResponse.success("该车牌号" + vehicleNumber  + "已经将消息发送到" + mailSource + "成功。");
    }

    /**
     * According to company id and communication type and communication source id and sms parameter for send mail.
     * @param companyId Company id.
     * @param messageType Message type.
     * @param messageSourceId Message source id.
     * @param vehicleNumber Vehicle number.
     * @param subject Mail subject.
     * @param operatorName Operator name.
     * @param messageSourceValue Message source code value.
     * @return Whether send success.
     */
    private boolean sendMail(Long companyId, Integer messageType, Integer messageSourceId,
                             String vehicleNumber, String subject, String operatorName,
                          String messageSourceValue) {
        boolean isSend = true;
        String mailToSource = "", operatorTime = DateUtil.format(DateUtil.YEAR_SECOND_PRETTY, new Date());
        QueryWrapper<NoticeMail> queryWrapper = new QueryWrapper();
        queryWrapper.lambda().eq(NoticeMail::getCompanyId, companyId)
                .eq(NoticeMail::getMailType, messageType)
                .eq(NoticeMail::getMailCode, messageSourceId);
        NoticeMail noticeMail = noticeMailService.getOne(queryWrapper);
        if(noticeMail != null) {
            if (subject.equals("")) {
                subject = noticeMail.getMailSubject();
            }
            String mailToCollections = noticeMail.getMailTo();

            if (StringUtil.isBlank(mailToCollections)) {
                log.error("Notice send to mail not found.");
                isSend = false;
            }

            if(isSend){
                try {
                    String[] mailTos = mailToCollections.split(",");
                    for (String mailTo : mailTos) {
                        mailToSource = mailTo;
                        MailDto mailDto = new MailDto();
                        mailDto.setSubject(subject);
                        mailDto.setFrom(noticeMail.getMailFrom());
                        mailDto.setTo(mailTo);
                        mailDto.setStatus(SendStatusEnum.SUCCESS.getFlag());

                        MessageTemplateDto messageTemplateDto = new MessageTemplateDto();
                        messageTemplateDto.setMailTo(mailTo);
                        messageTemplateDto.setVehicleNumber(vehicleNumber);
                        messageTemplateDto.setOperatorTime(operatorTime);
                        messageTemplateDto.setOperatorType(messageSourceValue);
                        CommunicationTemplate communicationTemplate = null;
                        if (MessageTypeEnum.ALARM.getMessageCode() == messageType) {
                            communicationTemplate = new AlarmCommunicationTemplate();
                        } else {
                            messageTemplateDto.setOperatorName(operatorName);
                            communicationTemplate = new VehicleCtlCommunicationTemplate();
                        }
                        String message = CommunicationBuilder.builder(new ConcreteCommunicationTemplate(communicationTemplate))
                            .compile(messageTemplateDto).orElse("");
                        mailDto.setText(message);
                        mailHelper.sendMail(mailDto);
                    }
                } catch (Exception ex) {
                    log.error("send {} mail find a fail, {}", mailToSource, ex);
                    isSend = false;
                }
            }

            noticeMail.setStatus(isSend ? StatusEnum.YES.getFlag() : StatusEnum.NO.getFlag());
            noticeMailService.saveOrUpdate(noticeMail);
        }
        return isSend;
    }

    /**
     * According to company id and communication type and communication source id and sms parameter for send sms.
     * @param companyId Company id.
     * @param messageType Message type.
     * @param messageSourceId Message source id.
     * @param vehicleNumber Vehicle number.
     * @param operatorName Operator name.
     * @param messageSourceValue Message source code value.
     * @param alarmLevel Alarm level.
     * @return Whether send success.
     */
    private boolean sendSMS(Long companyId, Integer messageType, Integer messageSourceId,
                            String vehicleNumber, String operatorName,
                             String messageSourceValue, Integer alarmLevel){
        boolean isSend = true;
        String operatorSuccessTime = DateUtil.format(DateUtil.YEAR_SECOND_PRETTY, new Date());
        QueryWrapper<NoticeSms> queryWrapper = new QueryWrapper();
        queryWrapper.lambda().eq(NoticeSms::getCompanyId, companyId)
                .eq(NoticeSms::getSmsType, messageType)
                .eq(NoticeSms::getSmsCode, messageSourceId);
        NoticeSms noticeSms = noticeSmsService.getOne(queryWrapper);
        if(noticeSms != null) {
            String mobile = noticeSms.getMobile();
            if (StringUtil.isBlank(mobile)) {
                log.error("Notice send to mobile not found.");
                isSend = false;
            }
            if(isSend){
                try {
                    SmsDto smsDto = new SmsDto();
                    smsDto.setMobile(mobile);
                    Map<String, Object> smsMap = new HashMap<>(4);
                    if (MessageTypeEnum.ALARM.getMessageCode() == messageType) {
                        noticeSms.setTempleteCode(smsProperties.getAlarmTemplateCode());
                        smsMap.put("alarmName", messageSourceValue);
                        smsMap.put("license", vehicleNumber);
                        smsMap.put("alarmLevel", alarmLevels[alarmLevel > 0 ? alarmLevel - 1 : alarmLevels.length - 1]);
                    } else {
                        noticeSms.setTempleteCode(smsProperties.getVehicleCtlTemplateCode());
                        smsMap.put("license", vehicleNumber);
                        smsMap.put("operSuccessTime", operatorSuccessTime);
                        smsMap.put("operator", operatorName);
                        smsMap.put("operatorTypeName", messageSourceValue);
                    }
                    smsDto.setTempleteCode(noticeSms.getTempleteCode());
                    smsDto.setJsonData(JsonUtils.toJson(smsMap));
                    isSend = smsHelper.sendSms(smsDto);
                } catch (Exception ex) {
                    log.error("send {} sms find a fail, {}", mobile, ex);
                    isSend = false;
                }
            }

            noticeSms.setStatus(isSend ? StatusEnum.YES.getFlag() : StatusEnum.NO.getFlag());
            noticeSmsService.saveOrUpdate(noticeSms);
        }
        return isSend;
    }

}
